#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "skfapi.h"
#include "skfapi_internal.h"
#include "mFS/FsTypes.h"
#include "System.h"
#include "SystemIO.h"
#include "log.h"
#ifdef _MSC_VER

#if _MSC_VER>=1900
#include <stdio.h>
#pragma comment(lib, "legacy_stdio_definitions.lib")
_ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);
FILE* __cdecl __iob_func(unsigned i) {
    return __acrt_iob_func(i);
}
#endif

#else
#include <unistd.h>
#endif

#ifndef WIN32
//#include <android/log.h>
//#define LOGD(LOG_TAG, ...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGD(LOG_TAG, ...)
#else
#define LOGD(LOG_TAG, ...)
#endif

char g_FingerId[128];
char g_FlashPath[256];
INITCONF g_conf;

#define  CONF_NAME  "/conf.ini"
#define  FLASH_NAME  "/VMKEY.F"
#define  CA_CERT_NAME "/CA.pem"
#define  CLIENT_ENC_CERT_KEY_NAME "/CE.pem"
#define  CLIENT_SIG_CERT_KEY_NAME "/CS.pem"

//如有空格切除空格，如有换行符切除换行符
static void CutBlankNewline(char *data)
{
	int i = strlen(data) - 1;

	for (i; i > 0; i--)
	{
		if (data[i] == '\r' || data[i] == '\n' || data[i] == ' ')
			data[i] = '\0';
		else
			return;//从字符串尾端开始，遇到第一个有效字符返回
	}
}
static int getitemvalue(char *filename, char *itemname, char *itemvalue)
{
	FILE *fp = NULL;
	char sLine[1024] = { 0 };
	char *value = NULL;

	if (NULL == (fp = fopen(filename, "r")))
	{
		return -1;
	}

	while (!feof(fp))
	{
		fgets(sLine, 1024, fp);
		if (strstr(sLine, itemname) == sLine)//该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串
		{
			value = strstr(sLine, "=");

			//去等号
			value++;

			//如有空格切除空格，如有换行符切除换行符
			CutBlankNewline(value);

			strcpy(itemvalue, value);

			fclose(fp);
			return 0;
		}
	}

	fclose(fp);
	return -1;
}
static int load_conf_file(char *path)
{
	int ret = 0;
	char value[256] = "\0";

	LOGD("MKEY:", "load_conf_file path: %s", path);

	/* »°∑˛ŒÒ∂Àipµÿ÷∑ */
	ret = getitemvalue(path, "ip", g_conf.ip);
	if (ret)
	{
		return ret;
	}

	LOGD("MKEY:", "load_conf_file ip ok");

	/* »°∑˛ŒÒ∂Àø⁄ */
	ret = getitemvalue(path, "port", value);
	if (ret)
	{
		return ret;
	}
	g_conf.port = atoi(value);

	LOGD("MKEY:", "load_conf_file port ok");

	/* »°≥¨ ± ±º‰ */
	ret = getitemvalue(path, "timeout", value);
	if (ret)
	{
		return ret;
	}
	g_conf.timeout = atoi(value);

	LOGD("MKEY:", "load_conf_file timeout ok");

	/* »°»’÷æº∂± */
	ret = getitemvalue(path, "loglevel", value);
	if (ret)
	{
		return ret;
	}
	g_conf.loglevel = atoi(value);

	LOGD("MKEY:", "load_conf_file loglevel ok");

	/* »°Õ®–≈¿‡–Õ */
	ret = getitemvalue(path, "ssltype", value);
	if (ret)
	{
		return ret;
	}
	g_conf.ssltype = atoi(value);

	LOGD("MKEY:", "load_conf_file ssltype ok");


	ret = getitemvalue(path, "ip_ca", g_conf.ip_ca);
	if (ret)
	{
		return ret;
	}

	LOGD("MKEY:", "load_conf_file ip_ca ok");

	/* »°∑˛ŒÒ∂Àø⁄ */
	ret = getitemvalue(path, "port_ca", value);
	if (ret)
	{
		return ret;
	}
	g_conf.port_ca = atoi(value);

	LOGD("MKEY:", "load_conf_file port_ca ok");

	
	return ret;

}
static int GlobalConfig_VMKey(char *path, char *devID)
{
	int rv = 0;
	char ConfPath[256] = { 0 };

	//全局设备id设置
	strncpy(g_FingerId, devID, strlen(devID));

	//全局flash地址设置
	strncpy(g_FlashPath, path, strlen(path));
	strcat(g_FlashPath, FLASH_NAME);

	//全局ip...等配置
	strncpy(ConfPath, path, strlen(path));
	strcat(ConfPath, CONF_NAME);
	rv = load_conf_file(ConfPath);
	if (rv)
		return rv;
	setLogLevel(g_conf.loglevel);//设置日志级别

	//全局证书地址配置
	strncpy(g_conf.CA_cert, path, strlen(path));
	strcat(g_conf.CA_cert, CA_CERT_NAME);
	strncpy(g_conf.client_enc_cert_key, path, strlen(path));
	strcat(g_conf.client_enc_cert_key, CLIENT_ENC_CERT_KEY_NAME);
	strncpy(g_conf.client_sig_cert_key, path, strlen(path));
	strcat(g_conf.client_sig_cert_key, CLIENT_SIG_CERT_KEY_NAME);

	return rv;
}
static int FlashFormat_VMKey(char *devID)
{
	//Flash不存在创建，格式化，并设置出厂信息
	int ret = 0;

	DEVINFO devInfo = { 0 };
	devInfo.Version.major = 1;
	devInfo.Version.minor = 0;
	strncpy((char*)devInfo.Manufacturer, "Longmai Tech", strlen("Longmai Tech"));
	strncpy((char*)devInfo.Issuer, "Longmai", strlen("Longmai"));
	strncpy((char*)devInfo.Label, "VMKey", strlen("VMKey"));
	memcpy(devInfo.SerialNumber, devID, 32);
	devInfo.HWVersion.major = 1;
	devInfo.HWVersion.minor = 0;
	devInfo.FirmwareVersion.major = 1;
	devInfo.FirmwareVersion.minor = 0;
	devInfo.AlgSymCap = SGD_SM4_ECB | SGD_SM4_CBC;
	devInfo.AlgAsymCap = SGD_SM2_1 | SGD_SM2_2 | SGD_SM2_3;
	devInfo.AlgHashCap = SGD_SM3 | SGD_SHA1 | SGD_SHA256;
	devInfo.DevAuthAlgId = SGD_SM4_ECB;
	devInfo.TotalSpace = 262144;//256*1024
	devInfo.FreeSpace = 0;
	devInfo.MaxECCBufferSize = 0;
	devInfo.MaxBufferSize = 0;
	memset(devInfo.Reserved, 0, sizeof(devInfo.Reserved));

	unsigned char dev_auth_key[32] = "1234567812345678";
	int nRetryTimes = 8;
	ULONG devNumber = 0;

	ret = MKF_FormatAllDev(&devInfo, dev_auth_key, strlen(dev_auth_key), "oemId_VMKey", (ULONG *)&nRetryTimes, (ULONG *)&nRetryTimes, &devNumber);

	return ret;
}

int SystemIO(unsigned char* pBuff, unsigned int* nLen)
{
	static int binit = 0;

	//	strcpy(g_FlashPath, DEFAULT_PATH);
	if (binit == 0)
	{
		System_Init();
		binit = 1;
	}
	System_Transmit(pBuff, *nLen);
	*nLen = System_RsponseLen();
	return 0;
}
int Init_VMKey(char *path, char *devID)
{
	int ret = 0;

	//全局变量初始化：g_FingerId / g_FlashPath / g_conf
	ret = GlobalConfig_VMKey(path, devID);
	if (ret)
		return ret;

	LOGD("MKEY:", "g_FingerId = %s", g_FingerId);
	LOGD("MKEY:", "g_FlashPath = %s", g_FlashPath);
	LOGD("MKEY:", "g_conf.ip = %s", g_conf.ip);
	LOGD("MKEY:", "g_conf.port = %d", g_conf.port);
	LOGD("MKEY:", "g_conf.ssltype = %d", g_conf.ssltype);
	LOGD("MKEY:", "g_conf.timeout = %d", g_conf.timeout);
	LOGD("MKEY:", "g_conf.loglevel = %d", g_conf.loglevel);
	LOGD("MKEY:", "g_conf.CA_cert = %s", g_conf.CA_cert);
	LOGD("MKEY:", "g_conf.client_enc_cert_key = %s", g_conf.client_enc_cert_key);
	LOGD("MKEY:", "g_conf.client_sig_cert_key = %s", g_conf.client_sig_cert_key);
	LOGD("MKEY:", "g_conf.ip_ca = %s", g_conf.ip_ca);
	LOGD("MKEY:", "g_conf.port_ca = %d", g_conf.port_ca);

	//检测flash文件是否存在,//flash文件创建，并设置出厂信息
	ret = access(g_FlashPath, 0);//F_OK
	if (ret)
		ret = FlashFormat_VMKey(g_FingerId);

	return ret;
}
int write_conf_vmkey_string(char *title, char *key, char *val, char *filename)
{
	int ret = 0;
	FILE *fpr, *fpw;
	int  flag = 0;
	char sLine[1024], sTitle[32], *wTmp;

	LOGD("MKEY:", "write_conf_vmkey_string filename: %s", filename);

	//拼接域名
	sprintf(sTitle, "[%s]", title);

	//检测配置文件是否存在
	if (NULL == (fpr = fopen(filename, "r")))
		return -1;

	LOGD("MKEY:", "write_conf_vmkey_string fopen read ok");

	//创建临时文件
	sprintf(sLine, "%s.tmp", filename);
	if (NULL == (fpw = fopen(sLine, "w")))
		return -2;

	LOGD("MKEY:", "write_conf_vmkey_string fopen write ok");

	while (NULL != fgets(sLine, 1024, fpr))
	{
		if (2 != flag)
		{ // 如果找到要修改的那一行，则不会执行内部的操作  
			wTmp = strchr(sLine, '=');

			LOGD("MKEY:", "write_conf_vmkey_string wTmp old: %s", wTmp);

			if ((NULL != wTmp) && (1 == flag))
			{
				if (0 == strncmp(key, sLine, wTmp - sLine))
				{ // 长度依文件读取的为准  
					flag = 2;// 更改值，方便写入文件  
					sprintf(wTmp + 1, "%s\n", val);

					LOGD("MKEY:", "write_conf_vmkey_string wTmp new: %s", wTmp);
				}
			}
			else
			{
				if (0 == strncmp(sTitle, sLine, strlen(sLine) - 1))
				{ // 长度依文件读取的为准  
					flag = 1; // 找到标题位置  
				}
			}
		}

		fputs(sLine, fpw); // 写入临时文件  
	}
	fclose(fpr);
	fclose(fpw);

	ret = remove(filename);
	if (ret)
		return -3;

	LOGD("MKEY:", "write_conf_vmkey_string remove ok");


	sprintf(sLine, "%s.tmp", filename);

	ret = rename(sLine, filename);
	if (ret)
		return -4;

	LOGD("MKEY:", "write_conf_vmkey_string rename ok");

	return ret;// 将临时文件更新到原文件  
}
int write_conf_vmkey_int(char *title, char *key, int val, char *filename)
{
	char sVal[32];
	sprintf(sVal, "%d", val);
	return write_conf_vmkey_string(title, key, sVal, filename);
}

int LoadVMKey_bk(char *path)
{
	strncpy(g_FlashPath, path, 256);
	return 0;
}
int LoadVMKey_ios(char *path, char *devID)
{
	int rv = 0;
	char ConfPath[256] = { 0 };

	//dev ID
	strncpy(g_FingerId, devID, strlen(devID));

	//flash path
	strncpy(g_FlashPath, path, strlen(path));
	strcat(g_FlashPath, FLASH_NAME);

	//conf path
	strncpy(ConfPath, path, strlen(path));
	strcat(ConfPath, CONF_NAME);

	rv = load_conf_file(ConfPath);

	strncpy(g_conf.CA_cert, path, strlen(path));
	strcat(g_conf.CA_cert, CA_CERT_NAME);

	strncpy(g_conf.client_enc_cert_key, path, strlen(path));
	strcat(g_conf.client_enc_cert_key, CLIENT_ENC_CERT_KEY_NAME);

	strncpy(g_conf.client_sig_cert_key, path, strlen(path));
	strcat(g_conf.client_sig_cert_key, CLIENT_SIG_CERT_KEY_NAME);

	return rv;
}
